#include "Mainwindow.h"
#include "assist.h"
#include <iostream>

#include <QApplication>
#include <QDir>
#include <QFileDialog>
#include <QGridLayout>
#include <QGroupBox>
#include <QProcess>
#include <QButtonGroup>
#include <QMouseEvent>
#include <QGraphicsItem>

using namespace std;

Imageview::Imageview(QWidget *parent)
	: QGraphicsView(parent) {
	scene = new QGraphicsScene();
	setScene(scene);
}

void Imageview::drawPointAt(const int x, const int y) {
	QPen *redpen = createPen(3, Qt::red);
	QGraphicsItem *temp;
	/* coords are divided by scale_factor here because they are in the original "cropped.jpg" */
	temp = scene->addLine((qreal)x, (qreal)y,
						  (qreal)x, (qreal)y, *redpen);
	temp->setZValue(1);
}

void Imageview::mousePressEvent(QMouseEvent *event) {
	if (event->button() != Qt::LeftButton)
		return;
    	
	selectedPoint = event->pos();
}

void Imageview::mouseMoveEvent(QMouseEvent *event) {}

void Imageview::mouseReleaseEvent(QMouseEvent *event) {	emit pointSelected(&selectedPoint); }

QPen *Imageview::createPen(int w, const QColor &color) {
	QPen *pen = new QPen();
	pen->setWidth(w);
	pen->setColor(color);
	return pen;
}

Mainwindow::Mainwindow(QWidget *parent)
	: QGraphicsView(parent) {
	
	setObjectName("Mainwindow");
	setWindowTitle("Image Foresting Transform Demo");

	/* Prepare Pushbuttons */
	browse = createButton(tr("Browse"), SLOT(browseFile()));
	generate = createButton(tr("Gradient"), SLOT(generateGradient()));
	start = createButton(tr("Start"), SLOT(beginIFT()));
	quitapp = createButton(tr("Quit"), SLOT(quit()));
	QButtonGroup *buttonGroup = new QButtonGroup;
	buttonGroup->addButton(browse);
	buttonGroup->addButton(generate);
	buttonGroup->addButton(start);
	buttonGroup->addButton(quitapp);
	foreach (QAbstractButton *button, buttonGroup->buttons())
		button->setMaximumWidth(120);

	inputView = new Imageview();
	gradientView = new Imageview();
	outputView = new Imageview();

	input = new QPixmap();
	gradient = new QPixmap();
	output = new QPixmap();
	
	QGridLayout *mainLayout = new QGridLayout;
	QVBoxLayout *buttonLayout = new QVBoxLayout;
	QGroupBox *gbMain = new QGroupBox("Controls");
	

	buttonLayout->addWidget(browse);
	buttonLayout->addWidget(generate);
	buttonLayout->addWidget(start);
	buttonLayout->addWidget(quitapp);
	gbMain->setLayout(buttonLayout);

	mainLayout->addWidget(inputView, 0, 0);
	mainLayout->addWidget(gradientView, 0, 1);
	mainLayout->addWidget(outputView, 1, 0);
	mainLayout->addWidget(gbMain, 1, 1);

	setLayout(mainLayout);
	start->setDisabled(true);
}

void Mainwindow::browseFile() {
	QString fileName = QFileDialog::getOpenFileName(this,
		tr("Open DICOM Image"), QDir::currentPath(), tr("DICOM Files (*.dcm *.jpg *.png)"));

	if (!fileName.isEmpty()) {
		if (fileName.endsWith("dcm")) {
			QProcess *dcm2jpg = new QProcess(this);
			QString program = "dcm2jpg.exe";
			QStringList arguments;
			arguments << fileName;
			
			cout << "Converting DCM to JPG...";
			dcm2jpg->start(program, arguments);
			dcm2jpg->waitForFinished();
			cout << "Done!" << endl;

			fileName.chop(3);
			fileName = fileName + "jpg";
		}
		/* Why only PNG works on object machines? *
		 * Otherwise, this piece is unnecessary.  */
		if (!fileName.endsWith("png")) {
			jpg2png(fileName.toAscii());
			fileName.chop(3);
			fileName = fileName + "png";
		}

		setCurrentImage(fileName, inputView, 1);
		jpgFile = fileName;
    }	
}

void Mainwindow::quit() {
	qApp->quit();
}

void Mainwindow::setCurrentImage(QString img, Imageview *view, int flag) {
	switch (flag) {
		case 1:
			delete input;
			input = new QPixmap(img);
			start->setDisabled(true);
			gradientView->clearScene();
			outputView->clearScene();
			break;
		case 2:
			delete gradient;
			gradient = new QPixmap(img);
			break;
		case 3:
			delete output;
			output = new QPixmap(img);
			break;
		default:
			cout << "Incorrect flag!" << endl;
			return;
	}
	view->clearScene();
	view->sceneAddPixmap(img);
}

void Mainwindow::generateGradient() {
	create_gradient_image(jpgFile.toAscii());

	//QString gradFile("gradient.jpg");
	QString gradFile("gradient.png");

	QFile temp(gradFile);
	if (temp.exists()) {
		setCurrentImage(gradFile, gradientView, 2);
		/* Reset the mouse position array */
		/* Or is it necessary? */
		//memset(mouse_pos, 0, sizeof(int) * 100);
		/* Reset mouse clicks (number of selected seed points) */
		clicks = 0;
		cout << "Please select seed points in the input image (Topleft Window)" << endl;
		connect(inputView, SIGNAL(pointSelected(QPoint *)), this, SLOT(addMousePos(QPoint *)));
	}
	else //cout << "Could not find \"gradient.jpg\"." << endl;
		cout << "Could not find \"gradient.png\"." << endl;
}

void Mainwindow::beginIFT() {
	run_ift(mouse_pos, clicks, jpgFile.toAscii());

	//QString outputFile("output.jpg");
	QString outputFile("output.png");
	QFile temp(outputFile);
	if (temp.exists()) {
		setCurrentImage(outputFile, outputView, 3);
		disconnect(inputView, SIGNAL(pointSelected(QPoint *)), this, SLOT(addMousePos(QPoint *)));
	}
	else //cout << "Could not find \"output.jpg\"." << endl;
		cout << "Could not find \"output.png\"." << endl;

}

void Mainwindow::addMousePos(QPoint *point) {

	QPointF scenePoint = inputView->mapToScene(*point);
	
	int x = scenePoint.x(), y = scenePoint.y();
	if (x >= 0 && y >= 0 && x < input->width() && y < input->height()) {
		mouse_pos[clicks * 2] = x;
		mouse_pos[clicks * 2 + 1] = y;
		clicks++;
		cout << "Selected seed: (" << x << ", " << y << ")" << endl;
		inputView->drawPointAt(x, y);
		start->setDisabled(false);
	}
	else cout << "Out of image boundary." << endl;
}

QPushButton *Mainwindow::createButton(const QString &text, const char *member1, const char *member2) {
    QPushButton *button = new QPushButton(text);
	if (member2 == NULL) {
		if (member1 != NULL)
			connect(button, SIGNAL(clicked()), this, member1);
	}
	else connect(button, member1, this, member2);
	button->setFont(QFont("Calibri", 12));
    return button;
}